package user

import (
	"errors"
	"strconv"
	"time"

	"gorm.io/gorm"

	"gitcode.com/G-YT/baoyou/server/model/system"
	"gitcode.com/G-YT/baoyou/server/model/user"

	"gitcode.com/G-YT/baoyou/server/global"
	"gitcode.com/G-YT/baoyou/server/model/common/response"
	userReq "gitcode.com/G-YT/baoyou/server/model/user/request"
	userRes "gitcode.com/G-YT/baoyou/server/model/user/response"
	"gitcode.com/G-YT/baoyou/server/utils"
	"gitcode.com/G-YT/baoyou/server/utils/sms"
	"github.com/gin-gonic/gin"
	"github.com/redis/go-redis/v9"
	"go.uber.org/zap"
)

const (
	MINI_APP_LATEST_ID     = "wxe91b20ae6c756b1d"
	MINI_APP_LATEST_SECRET = "2be19cabb3e3164727b096d6ef344555"
)

type UserApi struct {
}

// CodeLogin 验证码登陆
func (u *UserApi) CodeLogin(c *gin.Context) {
	var uc userReq.CodeLoginRequest
	err := c.ShouldBindJSON(&uc)
	if err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}
	err = utils.Verify(uc, utils.CodeLoginVerify)
	if err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}
	if smsErr := sms.CheckSMSCode(uc.Phone, uc.Code); smsErr != nil {
		response.Result(7, "", "验证码有误,请核实!", c)
		return
	}
	mu, upErr := UserService.UpsertLoginUser(uc.Phone, uc.ServiceStationID, uc.HealthManagerID, "code")
	if upErr != nil {
		response.FailWithMessage(upErr.Error(), c)
		return
	}
	u.TokenNextC(c, mu)
}

// PasswordLogin 密码登陆
func (u *UserApi) PasswordLogin(c *gin.Context) {
	var up userReq.LoginRequest
	err := c.ShouldBindJSON(&up)
	if err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}
	err = utils.Verify(up, utils.PasswordLoginVerify)
	if err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}
	_, existErr := UserService.FindUserByWhere(map[string]interface{}{"phone": up.Phone}, "*")
	// 如果不存在用户数据
	if errors.Is(existErr, gorm.ErrRecordNotFound) {
		// 去注册
		mu, upErr := UserService.UpsertLoginUser(up.Phone, 0, 0, "password")
		if upErr != nil {
			response.FailWithMessage(upErr.Error(), c)
			return
		}
		u.TokenNextC(c, mu)
		return
	}
	// 存在数据去校验登录
	userInfo := &user.User{Phone: up.Phone, Password: up.Password}
	userInter, loginErr := UserService.Login(userInfo)
	if loginErr != nil {
		response.FailWithMessage(loginErr.Error(), c)
		return
	}
	// 可以登陆去更新用户信息
	_, upErr := UserService.UpsertLoginUser(userInter.Phone, userInter.ServiceStationID, userInter.HealthManagerID, "password")
	if upErr != nil {
		response.FailWithMessage(upErr.Error(), c)
		return
	}
	u.TokenNextC(c, *userInter)
}

// OneClickLogin 一键登录
func (u *UserApi) OneClickLogin(c *gin.Context) {
	var req userReq.OneClickLoginRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}
	mu, upErr := UserService.UpsertLoginUser(req.Phone, req.ServiceStationID, req.HealthManagerID, "one_click")
	if upErr != nil {
		response.FailWithMessage(upErr.Error(), c)
		return
	}
	u.TokenNextC(c, mu)
}

// SetPassword 设置密码
func (u *UserApi) SetPassword(c *gin.Context) {
	var req userReq.SetPasswordRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}
	if req.Password == "" {
		response.FailWithMessage("密码不能为空", c)
		return
	}
	if req.Password != req.ConfirmPassword {
		response.FailWithMessage("两次输入的密码不一致", c)
		return
	}
	ID := utils.GetUserID(c)
	hashed := utils.BcryptHash(req.Password)
	if err := UserService.UpdateDataById(ID, map[string]interface{}{"password": hashed}); err != nil {
		response.FailWithMessage("修改失败", c)
		return
	}
	response.OkWithMessage("修改成功", c)
}

// GetUserData 获取用户信息
func (u *UserApi) GetUserData(c *gin.Context) {
	ID := utils.GetUserID(c)
	if ResUser, err := UserService.GetUserData(ID); err != nil {
		response.FailWithMessage("获取失败", c)
	} else {
		response.OkWithDetailed(ResUser, "获取成功", c)
	}
}

// UpdateUserData 修改用户信息
func (u *UserApi) UpdateUserData(c *gin.Context) {
	var req userReq.UpdateUserRequest
	err := c.ShouldBindJSON(&req)
	if err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}
	ID := utils.GetUserID(c)
	if err = UserService.UpdateUser(ID, req); err != nil {
		response.FailWithMessage("更新失败", c)
	} else {
		// 加分操作
		//UserService.AddPoints(req.ID, 10, 5)
		response.OkWithMessage("更新成功", c)
	}
}

// ChangePhone 更换绑定手机号
func (u *UserApi) ChangePhone(c *gin.Context) {
	var req userReq.ChangePhoneRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}
	// 判断更换的手机号是否已注册
	// 判断手机号是否存在
	_, existErr := UserService.FindUserByWhere(map[string]interface{}{"phone": req.Phone}, "*")
	if !errors.Is(existErr, gorm.ErrRecordNotFound) {
		response.FailWithMessage("手机号已注册,请核实", c)
		return
	}
	// 验证验证码
	if err := sms.CheckSMSCode(req.Phone, req.Code); err != nil {
		response.FailWithMessage("验证码错误,请核实", c)
		return
	}
	ID := utils.GetUserID(c)
	if err := UserService.UpdateDataById(ID, map[string]interface{}{"phone": req.Phone}); err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}
	response.OkWithMessage("更换成功", c)
}

// TokenNextC C端登入以后签发jwt
func (u *UserApi) TokenNextC(c *gin.Context, user user.User) {
	token, claims, err := utils.LoginTokenC(&user)
	if err != nil {
		global.GVA_LOG.Error("获取token失败!", zap.Error(err))
		response.FailWithMessage("获取token失败", c)
		return
	}
	if global.GVA_CONFIG.System.UseMultipoint {
		if err := utils.SetRedisJWT(token, "C:SignInToken:"+strconv.FormatUint(uint64(user.ID), 10)); err != nil {
			global.GVA_LOG.Error("设置登录状态失败!", zap.Error(err))
			response.FailWithMessage("设置登录状态失败", c)
			return
		}
		utils.SetToken(c, token, int(claims.RegisteredClaims.ExpiresAt.Unix()-time.Now().Unix()))
		response.OkWithDetailed(userRes.LoginResponse{
			ID:               user.ID,
			ServiceStationID: user.ServiceStationID,
			HealthManagerID:  user.HealthManagerID,
			Name:             user.Name,
			Avatar:           user.Avatar,
			Types:            user.Types,
			Token:            token,
			ExpiresAt:        claims.RegisteredClaims.ExpiresAt.Unix() * 1000,
		}, "登录成功", c)
		return
	}
	if jwtStr, err := jwtService.GetRedisJWT("C:SignInToken:" + strconv.FormatUint(uint64(user.ID), 10)); err == redis.Nil {
		if err := utils.SetRedisJWT(token, "C:SignInToken:"+strconv.FormatUint(uint64(user.ID), 10)); err != nil {
			global.GVA_LOG.Error("设置登录状态失败!", zap.Error(err))
			response.FailWithMessage("设置登录状态失败", c)
			return
		}
		utils.SetToken(c, token, int(claims.RegisteredClaims.ExpiresAt.Unix()-time.Now().Unix()))
		response.OkWithDetailed(userRes.LoginResponse{
			ID:               user.ID,
			ServiceStationID: user.ServiceStationID,
			HealthManagerID:  user.HealthManagerID,
			Name:             user.Name,
			Avatar:           user.Avatar,
			Types:            user.Types,
			Token:            token,
			ExpiresAt:        claims.RegisteredClaims.ExpiresAt.Unix() * 1000,
		}, "登录成功", c)
	} else if err != nil {
		global.GVA_LOG.Error("设置登录状态失败!", zap.Error(err))
		response.FailWithMessage("设置登录状态失败", c)
	} else {
		var blackJWT system.JwtBlacklist
		blackJWT.Jwt = jwtStr
		if err := jwtService.JsonInBlacklist(blackJWT); err != nil {
			response.FailWithMessage("jwt作废失败", c)
			return
		}
		if err := utils.SetRedisJWT(token, "C:SignInToken:"+strconv.FormatUint(uint64(user.ID), 10)); err != nil {
			response.FailWithMessage("设置登录状态失败", c)
			return
		}
		utils.SetToken(c, token, int(claims.RegisteredClaims.ExpiresAt.Unix()-time.Now().Unix()))
		response.OkWithDetailed(userRes.LoginResponse{
			ID:               user.ID,
			ServiceStationID: user.ServiceStationID,
			HealthManagerID:  user.HealthManagerID,
			Name:             user.Name,
			Avatar:           user.Avatar,
			Types:            user.Types,
			Token:            token,
			ExpiresAt:        claims.RegisteredClaims.ExpiresAt.Unix() * 1000,
		}, "登录成功", c)
	}
}
